﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace InDepth2Demo.Chapter6
{
    /// <summary>
    /// 6.2 C# 2:利用 yield 语句简化迭代器
    /// </summary>
    public class YieldIterator
    {
        /// <summary>
        /// 6.2.2 观察迭代器的工作流程
        /// </summary>
        static readonly string Padding = new string(' ', 30);

        static IEnumerable<int> CreateEnumerable()
        {
            Console.WriteLine("{0}Start of CreateEnumerable()", Padding);

            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("{0}About to yield {1}", Padding, i);
                yield return i;
                Console.WriteLine("{0}After yield", Padding);
            }

            Console.WriteLine("{0}Yielding final value", Padding);
            yield return -1;
            Console.WriteLine("{0}End of CreateEnumerable()", Padding);
        }

        public static void Call()
        {
            IEnumerable<int> iterable = CreateEnumerable();
            IEnumerator<int> iterator = iterable.GetEnumerator();
            Console.WriteLine("Starting to iterate");
            while (true)
            {
                Console.WriteLine("Calling MoveNext()...");
                bool result = iterator.MoveNext();
                Console.WriteLine("... MoveNext result={0}", result);
                if (!result)
                {
                    break;
                }
                Console.WriteLine("Fetching Current...");
                Console.WriteLine("... Current result={0}", iterator.Current);
            }
        }

        static IEnumerable<int> CountWithTimeLimit(DateTime limit)
        {
            try
            {
                Console.WriteLine("enter");
                for (int i = 0; i < 100; i++)
                {
                    if (DateTime.Now >= limit)
                    {
                        Console.WriteLine("yield break");
                        yield break;                        // 如果时间到了就停止运行
                    }
                    Console.WriteLine($"yield return {i}");
                    yield return i;
                }
            }
            finally
            {
                Console.WriteLine("Stopping!");
            }
        }

        public static void Call2()
        {
            DateTime stop = DateTime.Now.AddSeconds(2);
            foreach (var item in CountWithTimeLimit(stop))
            {
                Console.WriteLine($"Received {item}");
                if (item > 3)
                {
                    Console.WriteLine("returning");
                    return;
                }
                Thread.Sleep(300);
            }
        }
    }
}
